package com.bowlong.net.proto.gen3;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Map;

import org.apache.poi.xssf.usermodel.XSSFRow;

import com.bowlong.lang.PStr;
import com.bowlong.lang.StrEx;
import com.bowlong.tool.Lib2;
import com.bowlong.util.MapEx;
import com.bowlong.util.NewList;
import com.bowlong.util.NewMap;
import com.bowlong.util.StrBuilder;

@SuppressWarnings({ "unused", "resource", "rawtypes", "unchecked" })
public class Bio3GJava extends Lib2 {
	public static void b2g(Class<?> c, boolean src) throws Exception {
		String retname = "ReturnStatus";
		b2g(c, src, retname);
	}

	public static void b2g(Class<?> c, boolean src, String retname) {
		B3Class B2C = c.getAnnotation(B3Class.class);
		String namespace = "";
		if (B2C != null) {
			namespace = B2C.namespace();
		}
		Class<?>[] classes = c.getDeclaredClasses();
		String p = (src ? "src/" : "") + "gen_b2g";
		// String p = "gen_b2g";

		if (namespace != null && !namespace.isEmpty()) {
			p = p + "/" + namespace;
		}

		for (Class<?> class1 : classes) {
			String sname = class1.getSimpleName();
			if (B3G.isServer(class1)) {
				File path = new File(p);
				if (!path.exists())
					path.mkdirs();

				{
					StrBuilder sb = new StrBuilder();
					g2s_service(class1, namespace, retname, sb);
					writeFile(p + "/" + sname + ".java", sb.toString());
					System.out.println(sb);
				}
				{
					StrBuilder sb2 = new StrBuilder();
					g2s_call(class1, namespace, retname, sb2);
					writeFile(p + "/" + "Call" + sname + ".java",
							sb2.toString());
					System.out.println(sb2);
				}
			} else if (B3G.isData(class1)) {
				String p2 = p + "/bean";
				File path = new File(p2);
				if (!path.exists())
					path.mkdirs();

				String f = class1.getSimpleName();
				StrBuilder sb = new StrBuilder();
				if (B3G.isConstant(class1)) {
					g2beanConstant(class1, namespace, sb);
				} else {
					g2bean(class1, namespace, sb);
				}
				writeFile(p2 + "/" + f + ".java", sb.toString());
				System.out.println(sb);
			}
		}

		excel(p, c, classes, namespace);

	}

	public static void excel(String p, Class<?> c, Class<?>[] classes,
			String namespace) {
		if (!B3G.isExcel(c))
			return;
		String cn = c.getSimpleName();
		StrBuilder sb = new StrBuilder();
		StrBuilder sb1 = new StrBuilder();
		StrBuilder sb2 = new StrBuilder();
		String className = "Sheets";
		sb.pn("package gen_b2g${1}.bean;", isEmpty(namespace) ? "" : "."
				+ namespace);
		sb.pn("public class ${1} {", className);
		for (Class<?> c1 : classes) {
			if (B3G.isSheet(c1)) {
				String cname = c1.getSimpleName();
				String sheetName = B3G.getSheetName(c1);
				String cname2 = StrEx.left(cname, cname.length() - 1);
				sb1.ap("$[1], ", sheetName);
				sb2.ap("$[1], ", sheetName + ".pb.bytes");
				sb.pn("    public static final String SHEET_${1} = $[2];",
						sheetName.toUpperCase(), sheetName);
				sb.pn("    public static final String FN_${1} = $[2];",
						sheetName.toUpperCase(), sheetName.toLowerCase()
								+ ".pb.bytes");
				sb.pn("");
			}
		}
		sb1.removeRight(2);
		sb2.removeRight(2);
		String str1 = sb1.toString();
		String str2 = sb2.toString();
		sb.pn("    public static final String[] sheets = {${1}};", str1);
		sb.pn("    public static final String[] files = {${1}};", str2);
		sb.pn("}");
		String result = sb.toString();

		String p2 = p + "/bean";
		writeFile(p2 + "/" + className + ".java", result);
	}

	public static void g2bean(Class<?> c, String namespace, StrBuilder sb) {
		// Field[] fs = c.getDeclaredFields();
		Field[] fs = B3G.getFields(c);
		String cname = c.getSimpleName();
		int hcname = hashCode(cname);
		sb.pn("package gen_b2g${1}.bean;", StrEx.isEmpty(namespace) ? "" : "."
				+ namespace);
		sb.pn("");
		sb.pn("import java.io.*;");
		sb.pn("import java.util.*;");
		sb.pn("");
		sb.pn("import com.bowlong.util.*;");
		if (B3G.isSheet(c)) {
			sb.pn("import com.bowlong.io.*;");
			sb.pn("import org.apache.poi.xssf.usermodel.*;");
			sb.pn("import com.bowlong.net.http.*;");
		} else if (B3G.isSheetRow(c)) {
			sb.pn("import org.apache.poi.xssf.usermodel.*;");
			sb.pn("import com.bowlong.third.xss.*;");
		}

		sb.pn("");
		// sb.pn("@SuppressWarnings({ \"rawtypes\", \"unchecked\", \"serial\", \"unused\" })");
		sb.pn("@SuppressWarnings({ \"rawtypes\", \"unchecked\" })");
		sb.pn("public class ${1} extends com.bowlong.net.proto.N3Support {",
				cname);
		sb.pn("    public static final int _CID = ${1};", hcname);
		sb.pn("");

		StrBuilder sb0 = new StrBuilder();
		int i = 0;
		for (Field field : fs) {
			B3Field a = field.getAnnotation(B3Field.class);
			String t = B3G.getType(field);
			String s = field.getName();
			if (s.contains("$"))
				continue;
			if (i == 0) {
				sb0.ap("${1} ${2}", t, s);
			} else {
				sb0.ap(",${1} ${2}", t, s);
			}
			i++;
			String remark = B3G.getRemark(field);
			if (field.getType().equals(List.class)) {
				String gtype = B3G.getListType(field);
				if (gtype != null && !gtype.isEmpty()) {
					sb.pn("    public ${1}<${4}> ${2} = new NewList(); ${3}",
							t, s, remark, gtype);
				}
			} else {
				if (t.contains("String")) {
					sb.pn("    public ${1} ${2} = \"\"; ${3}", t, s, remark);
				} else if (t.contains("Map")) {
					sb.pn("    public ${1} ${2} = new NewMap(); ${3}", t, s,
							remark);
				} else {
					if (B3G.isBType(t)) {
						sb.pn("    public ${1} ${2}; ${3}", t, s, remark);
					} else {
						sb.pn("    public ${1} ${2} = new ${1}(); ${3}", t, s,
								remark);

					}
				}
			}
		}

		// ///////
		sb.pn("");
		sb.pn("    public ${1} set${2}(${3}){", cname, cname, sb0.toString());
		for (Field field : fs) {
			String t = B3G.getType(field);
			String gm = B3G.getMapType(t);
			String s = field.getName();
			if (s.contains("$"))
				continue;
			sb.pn("        this.${1} = ${2};", s, s);
		}
		sb.pn("        return this;");
		sb.pn("    }");

		sb.pn("");
		sb.pn("    public ${1}(){}", cname);
		sb.pn("");
		sb.pn("    public ${1}(${2}){", cname, sb0.toString());
		for (Field field : fs) {
			String t = B3G.getType(field);
			String gm = B3G.getMapType(t);
			String s = field.getName();
			if (s.contains("$"))
				continue;
			sb.pn("        this.${1} = ${2};", s, s);
		}
		sb.pn("    }");
		sb.pn("");

		sb.pn("    public ${1}(NewMap map2) {", cname);
		for (Field field : fs) {
			String t = B3G.getType(field);
			String gm = B3G.getMapType(t);
			String s = field.getName();
			int hs = s.hashCode();
			if (s.contains("$"))
				continue;

			if (field.getType().equals(List.class)) {
				String gtype = B3G.getListType(field);
				boolean isBType = B3G.isBType(gtype);
				if (gtype != null && !gtype.isEmpty() && !isBType) {
					sb.pn("        this.${1} = maps_${1}( map2.getList(${3}) );",
							s, gm, hs, gtype);
				} else {
					sb.pn("        this.${1} = map2.${2}(${3});", s, gm, hs);
				}
			} else {
				if (gm.equals("getObject")) {
					sb.pn("        this.${1} = ${2}.parse(map2.getNewMap(${3}));",
							s, t, hs);
				} else {
					sb.pn("        this.${1} = map2.${2}(${3});", s, gm, hs);
				}
			}
		}
		sb.pn("    }");
		sb.pn("");

		if (B3G.isSheetRow(c)) {
			sb.pn("    public ${1} (XSSFRow row) {", cname);
			sb.pn("        int _xcol = 0;");
			for (Field field : fs) {
				String t = B3G.getType(field);
				String gm = B3G.getMapType(t);
				String s = field.getName();
				int hs = s.hashCode();
				if (s.contains("$"))
					continue;
				sb.pn("        this.${1} = XSS.${2}(row, _xcol++);", s, gm);
			}
			sb.pn("    }");
		}
		// /

		for (Field field : fs) {
			String s = field.getName();
			if (s.contains("$"))
				continue;
			String s1 = StrEx.upperFirst(s);
			String t = B3G.getType(field);
			if (field.getType().equals(List.class)) {
				String gtype = B3G.getListType(field);
				boolean isBtype = B3G.isBType(gtype);
				if (gtype != null && !gtype.isEmpty() && !isBtype) {
					sb.pn("    public List<Map> ${1}_maps() {", s);
					sb.pn("        List<Map> r = new NewList<Map>();");
					sb.pn("        if(${1} == null) return r;", s);
					sb.pn("        for(${1} _e : ${2}) {", gtype, s);
					sb.pn("            Map e = _e.toMap();");
					sb.pn("            if(e == null) continue;");
					sb.pn("            r.add(e);");
					sb.pn("        }");
					sb.pn("        return r;");
					sb.pn("    }");
					sb.pn("");

					sb.pn("    public static List<${2}> maps_${1}(List<Map> maps) {",
							s, gtype);
					sb.pn("        List r = new NewList();");
					sb.pn("        for(Map _e : maps) {", gtype, s);
					sb.pn("            NewMap _map = NewMap.create(_e);",
							gtype, s);
					sb.pn("            ${1} e = ${1}.parse(_map);", gtype);
					sb.pn("            if(e == null) continue;");
					sb.pn("            r.add(e);");
					sb.pn("        }");
					sb.pn("        return r;");
					sb.pn("    }");
					sb.pn("");
				}
			}
		}

		sb.pn("");
		sb.pn("    public Map _cacheResult;");
		sb.pn("    public Map toMap() {");
		sb.pn("        if(_cacheResult != null && !_cacheResult.isEmpty())");
		sb.pn("           return _cacheResult;");
		sb.pn("        Map r = new HashMap();");
		sb.pn("        r.put(${1}, _CID);", B3G.BEAN);
		for (Field field : fs) {
			String t = B3G.getType(field);
			String gm = B3G.getMapType(t);
			String s = field.getName();
			int hs = s.hashCode();
			if (s.contains("$"))
				continue;

			if (field.getType().equals(List.class)) {
				String gtype = B3G.getListType(field);
				boolean isBType = B3G.isBType(gtype);
				if (gtype != null && !gtype.isEmpty() && !isBType) {
					sb.pn("        r.put(${1}, ${2}_maps());", hs, s);
				} else {
					sb.pn("        r.put(${1}, ${2});", hs, s);
				}
			} else {
				if (gm.equals("getObject")) {
					sb.pn("        r.put(${1}, ${2}.toMap());", hs, s);
				} else {
					sb.pn("        r.put(${1}, ${2});", hs, s);
				}
			}
		}
		sb.pn("        return r;");
		sb.pn("    }");
		sb.pn("");

		sb.pn("");
		sb.pn("    public static ${1} parse(NewMap map2) {", cname);
		sb.pn("        ${1} r = new ${1}(map2);", cname);
		sb.pn("        return r;");
		sb.pn("    }");
		sb.pn("");

		sb.pn("");
		sb.pn("    public static ${1} parse(NewMap map2, ${1} r) {", cname);
		sb.pn("        if(map2 == null) return null;");
		sb.pn("");
		for (Field field : fs) {
			String t = B3G.getType(field);
			String gm = B3G.getMapType(t);
			String s = field.getName();
			int hs = s.hashCode();
			if (s.contains("$"))
				continue;

			if (field.getType().equals(List.class)) {
				String gtype = B3G.getListType(field);
				boolean isBType = B3G.isBType(gtype);
				if (gtype != null && !gtype.isEmpty() && !isBType) {
					sb.pn("        r.${1} = maps_${1}( map2.getList(${3}) );",
							s, gm, hs, gtype);
				} else {
					sb.pn("        r.${1} = map2.${2}(${3});", s, gm, hs);
				}
			} else {
				if (gm.equals("getObject")) {
					sb.pn("        r.${1} = ${2}.parse(map2.getNewMap(${3}));",
							s, t, hs);
				} else {
					sb.pn("        r.${1} = map2.${2}(${3});", s, gm, hs);
				}
			}
		}
		sb.pn("        return r;");
		sb.pn("    }");
		sb.pn("");

		StrBuilder sbts = new StrBuilder();
		sbts.a("\"").a(cname).a("[");
		for (Field field : fs) {
			String t = B3G.getType(field);
			String gm = B3G.getMapType(t);
			String s = field.getName();
			if (s.contains("$"))
				continue;
			sbts.a("").a(s).a("=\" + ").a(s).a(" + \", ");
		}
		sbts.removeRight(2);
		sbts.a("]\"");
		sb.pn("    public String toString() {");
		sb.pn("        return ${1};", sbts);
		sb.pn("    }");
		sb.pn("");

		sb.pn("    public static ${1} parse(byte[] buf) throws Exception {",
				cname);
		sb.pn("        Map<Object, Object> map = com.bowlong.bio3.B3Helper.parseMap(buf);");
		sb.pn("        NewMap map2 = NewMap.create(map);");
		sb.pn("        return parse(map2);");
		sb.pn("    }");
		sb.pn("");

		sb.pn("    public static ${1} parse(InputStream in) throws Exception {",
				cname);
		sb.pn("        Map<Object, Object> map = com.bowlong.bio3.B3Helper.parseMap(in);");
		sb.pn("        NewMap map2 = NewMap.create(map);");
		sb.pn("        return parse(map2);");
		sb.pn("    }");
		sb.pn("");

		sb.pn("    public byte[] toByteArray() throws Exception {");
		sb.pn("        return com.bowlong.bio3.B3Helper.toBytes(toMap());");
		sb.pn("    }");
		sb.pn("");

		if (B3G.isSheet(c)) {
			String sheetName = B3G.getSheetName(c);
			String sheetIndexs = B3G.getSheetIndexs(c);
			String cname2 = StrEx.left(cname, cname.length() - 1);
			sb.pn("    /////////////////// ");
			sb.pn("    public static ${1} CACHED;", cname);
			sb.pn("    public static ${1}[] CACHE_ARRAY;", cname2);
			sb.pn("    static final Map<MultiKey2, Set<Integer>> QCACHE = new Hashtable<>();");
			sb.pn("");
			sb.pn("    public static ${1} hit1(MultiKey2 key) {", cname2);
			sb.pn("        Set<Integer> list = QCACHE.get(key);");
			sb.pn("        if (list == null)");
			sb.pn("            return null;");
			sb.pn("        for (Integer id : list)");
			sb.pn("            return CACHE_ARRAY[id];");
			sb.pn("        return null;");
			sb.pn("    }");
			sb.pn("");
			sb.pn("    public static List<${1}> hits(MultiKey2 key) {", cname2);
			sb.pn("        List<${1}> r2 = new ArrayList<>();", cname2);
			sb.pn("        Set<Integer> list = QCACHE.get(key);");
			sb.pn("        if (list == null)");
			sb.pn("            return r2;");
			sb.pn("        for (Integer id : list)");
			sb.pn("            r2.add(CACHE_ARRAY[id]);");
			sb.pn("        return r2;");
			sb.pn("    }");
			sb.pn("");
			sb.pn("    public static void cache(MultiKey2 key, ${1} v) {", cname2);
			sb.pn("        if (key == null || v == null)");
			sb.pn("            return;");
			sb.pn("        Set<Integer> list = QCACHE.get(key);");
			sb.pn("        if (list == null) {");
			sb.pn("            list = new HashSet<>();");
			sb.pn("            QCACHE.put(key, list);");
			sb.pn("        }");
			sb.pn("        list.add(v.ID);");
			sb.pn("    }");
			sb.pn("");
			sb.pn("    public static void cache(MultiKey2 key, List<${1}> vals) {",
					cname2);
			sb.pn("        if (key == null || vals == null || vals.isEmpty())");
			sb.pn("            return;");
			sb.pn("        Set<Integer> list = QCACHE.get(key);");
			sb.pn("        if (list == null) {");
			sb.pn("            list = new HashSet<>();");
			sb.pn("            QCACHE.put(key, list);");
			sb.pn("        }else");
			sb.pn("            list.clear();");
			sb.pn("");
			sb.pn("        for (${1} v : vals)", cname2);
			sb.pn("            list.add(v.ID);");
			sb.pn("    }");
			sb.pn("");
			sb.pn("    public static void loadToCache(String path) throws Exception {",
					cname);
			sb.pn("        CACHED = parse(path);");
			sb.pn("        loadToCache(CACHED);");
			sb.pn("    }");
			sb.pn("    public static void loadToCacheBaseURL(String baseUrl) throws Exception {",
					cname);
			sb.pn("        java.net.URL url = new java.net.URL(fn(baseUrl));");
			sb.pn("        byte[] buf = HttpEx.readUrl(url);");
			sb.pn("        Log.info(url + \" - (length:\" + buf.length + \")\");");
			sb.pn("        try(InputStream in = new ByteArrayInputStream(buf);) {");
			sb.pn("            loadToCache(in);");
			sb.pn("        }");
			sb.pn("    }");
			sb.pn("    public static void loadToCache(InputStream in) throws Exception {",
					cname);
			sb.pn("        CACHED = parse(in);");
			sb.pn("        loadToCache(CACHED);");
			sb.pn("    }");
			sb.pn("    public static void loadToCache(${1} data) {", cname);
			sb.pn("        CACHED = data;");
			sb.pn("        int MAXID = data.datas.get(data.datas.size() - 1).ID;");
			sb.pn("        CACHE_ARRAY = new ${1}[MAXID + 1];", cname2);
			sb.pn("        QCACHE.clear();");
			sb.pn("        for (${1} e : data.datas) {", cname2);
			sb.pn("            CACHE_ARRAY[e.ID] = e;");
			// 索引查询器
			List<Map> indexs = parseList(sheetIndexs);
			for (Map map : indexs) {
				String type = MapEx.getString(map, "type"); // ix , ux
				List<Map> fields = MapEx.getList(map, "fields");
				String cps = getSheetIndexParams(fields);
				if (type.equals("ux")) {
					sb.pn("            { ");
					sb.pn("                MultiKey2 mkey = new MultiKey2(${1});",
							cps);
					sb.pn("                cache(mkey, e);");
					sb.pn("            }");
				}
			}
			sb.pn("        }");
			sb.pn("    }");
			sb.pn("    public static ${1} getById(int id) {", cname2);
			sb.pn("        return CACHE_ARRAY[id];");
			sb.pn("    }");
			sb.pn("    public static List<${1}> getAll() {", cname2);
			sb.pn("        return CACHED.datas;");
			sb.pn("    }");
			sb.pn("    /////////////////// ");
			sb.pn("");
			sb.pn("    public static final String sheetName = $[1];", sheetName);
			sb.pn("    public static final String fn = $[1];",
					sheetName.toLowerCase() + ".pb.bytes");
			sb.pn("    public static final String fn(String path) {");
			sb.pn("        return path + fn;");
			sb.pn("    }");
			sb.pn("");
			sb.pn("    public static ${1} parse(String path) throws Exception {",
					cname);
			sb.pn("        File f = new File(fn(path));");
			sb.pn("        byte[] b = FileEx.readFully(f);");
			sb.pn("        return parse(b);");
			sb.pn("    }");
			sb.pn("");
			sb.pn("    public static final ${1} parse(XSSFWorkbook wb) {",
					cname);
			sb.pn("        XSSFSheet sheet = wb.getSheet(sheetName);");
			sb.pn("        int MAX_ROW = sheet.getLastRowNum();", cname);
			sb.pn("        ${1} r2 = new ${1}();", cname);
			sb.pn("        for (int rownum = 3; rownum <= MAX_ROW; rownum++) {");
			sb.pn("            XSSFRow row = sheet.getRow(rownum);");
			sb.pn("            ${1} e = ${1}.parse(row);", cname2);
			sb.pn("            if (e == null)");
			sb.pn("                break;");
			sb.pn("            r2.datas.add(e);");
			sb.pn("        }");
			sb.pn("        return r2;");
			sb.pn("    }");
			sb.pn("");

			// 索引查询器
			// List<Map> indexs = parseList(sheetIndexs);
			for (Map map : indexs) {
				String type = MapEx.getString(map, "type"); // ix , ux
				List<Map> fields = MapEx.getList(map, "fields");
				String indexMethod = getSheetIndexMethod(cname2, map);
				String rst = getSheetIndexReturn(cname2, type);
				String rstInit = getSheetIndexReturnInit(cname2, type);
				String eqs = getSheetIndexMethodEq(fields);
				String cps = getSheetCallParams(fields);
				sb.pn("    public static ${1} {", indexMethod);
				sb.pn("        MultiKey2 mkey = new MultiKey2(${1});", cps);
				if (type.equals("ix")) {
					sb.pn("        ${1} r2 = hits(mkey);", rst);
					sb.pn("        if(r2 != null && !r2.isEmpty())");
					sb.pn("            return r2;");
					// sb.pn("        r2 = ${1};", rstInit);
				} else {
					sb.pn("        ${1} r2 = hit1(mkey);", rst);
					sb.pn("        if(r2 != null)");
					sb.pn("            return r2;");
				}
				sb.pn("");
				// sb.pn("        ${1} r2 = ${2};", rst, rstInit);
				sb.pn("        List<${1}> datas = getAll();", cname2);
				sb.pn("        for (${1} e : datas) {", cname2);
				sb.pn("            if(${1}) {", eqs);
				if (type.equals("ix"))
					sb.pn("                r2.add(e);");
				else {
					sb.pn("                r2 = e;");
					sb.pn("                break;");
				}
				sb.pn("            }");
				sb.pn("        }");
				sb.pn("        cache(mkey, r2);");
				sb.pn("        return r2;");
				sb.pn("    }");
			}
		}
		if (B3G.isSheetRow(c)) {
			sb.pn("    public static ${1} parse(XSSFRow row) {", cname);
			sb.pn("        int __xid = XSS.getInt(row, 0);");
			sb.pn("        if (__xid < 0)");
			sb.pn("            return null;");
			sb.pn("        ${1} r2 = new ${1}(row);", cname);
			sb.pn("        return r2;");
			sb.pn("        ");
			sb.pn("    }");
		}

		sb.pn("}");

	}

	public static void g2beanConstant(Class<?> c, String namespace,
			StrBuilder sb) {
		// Field[] fs = c.getDeclaredFields();
		Field[] fs = B3G.getFields(c);
		String cname = c.getSimpleName();
		sb.pn("package gen_b2g${1}.bean;", StrEx.isEmpty(namespace) ? "" : "."
				+ namespace);
		sb.pn("");
		sb.pn("public class ${1} {", cname);
		for (Field field : fs) {
			B3Field a = field.getAnnotation(B3Field.class);
			String t = B3G.getType(field);
			String s = field.getName();
			if (s.contains("$"))
				continue;

			String remark = B3G.getRemark(field);
			String def = B3G.getDef(field);
			if ("".equals(def)) {
				continue;
			}
			if (field.getType().equals(List.class)) {
				continue;
			} else {
				if (t.contains("String")) {
					sb.pn("    public static final ${1} ${2} = \"${4}\"; ${3}",
							t, s, remark, def);

				} else {
					sb.pn("    public static final ${1} ${2} = ${4}; ${3}", t,
							s, remark, def);
				}
			}
		}
		sb.pn("}");
	}

	// 生成服务器接口
	public static void g2s_service(Class<?> c, String namespace,
			String retname, StrBuilder sb) {
		Method[] methods = c.getMethods();
		String cname = c.getSimpleName();
		sb.pn("package gen_b2g${1};", StrEx.isEmpty(namespace) ? "" : "."
				+ namespace);
		// sb.pn("package gen_b2g;");
		sb.pn("");
		sb.pn("import java.io.*;");
		sb.pn("import java.util.*;");
		sb.pn("");
		sb.pn("import com.bowlong.io.*;");
		sb.pn("import com.bowlong.util.*;");
		sb.pn("import com.bowlong.net.*;");
		sb.pn("");
		sb.pn("import gen_b2g${1}.bean.*;", StrEx.isEmpty(namespace) ? "" : "."
				+ namespace);
		sb.pn("");
		sb.pn("@SuppressWarnings({ \"rawtypes\", \"unchecked\", \"unused\" })");
		sb.pn("public abstract class ${1} extends com.bowlong.net.proto.N3Support {",
				cname);
		sb.pn("");
		sb.pn("public abstract TcpChannel chn(int XID) throws Exception;");
		sb.pn("");
		for (Method m : methods) { // 向客户端主动发送
			if (!B3G.isClient(m))
				continue;
			String remark = B3G.getRemark(m);
			// String oType = B2G.getOType(m);
			String srtype = B3G.getReturnType(m);
			String mname = B3G.getNethodName(m);
			int hmname = hashCode(cname, mname);
			NewList<NewMap<String, String>> params = B3G.getParameters(m);

			StrBuilder sb1 = new StrBuilder();
			StrBuilder sb2 = new StrBuilder();
			for (NewMap<String, String> m1 : params) {
				String key = (String) m1.getKey();
				String val = (String) m1.getValue();
				// StrBuilder sb0 = new StrBuilder();
				if (B3G.getMapType(key).equals("getList")) {
					key = PStr.str("${1}<${2}>", key, B3G.getOType(m, val));
					// sb0.ap("${1}<${2}>", key, B2G.getOType(m, val));
					// key = sb0.toString();
				}
				sb1.ap(", ${1} ${2}", key, val);
				sb2.ap(", ${1}", val);
			}

			sb.pn("    // //////////////////////////////////////////////");
			sb.pn("    // 逻辑调用");
			sb.pn("    // //////////////////////////////////////////////");
			sb.pn("");
			sb.pn("    // ${1}", remark);
			sb.pn("    public void ${1}(int XID ${2}) throws Exception {",
					mname, sb1);
			sb.pn("        TcpChannel chn = chn(XID);");
			sb.pn("        ${1}(chn${2});", mname, sb2);
			sb.pn("    }");
			// sb.pn("    public void ${1}(int XID, List<Integer> xids2 ${2}) throws Exception {",
			// mname, sb1);
			// sb.pn("        TcpChannel chn = chn(XID);");
			// sb.pn("        List<TcpChannel> chn2 = new NewList<TcpChannel>();");
			// sb.pn("        if (xids2 != null) {");
			// sb.pn("        	for (Integer _xid2 : xids2) {");
			// sb.pn("        		TcpChannel _chn = chn(XID);");
			// sb.pn("        		if(_chn != null) chn2.add(_chn);");
			// sb.pn("        	}");
			// sb.pn("        }");
			// sb.pn("        ${1}(chn,chn2${2});", mname, sb2);
			// sb.pn("    }");
			sb.pn("    public void ${1}(TcpChannel chn ${2}) throws Exception {",
					mname, sb1);
			// sb.pn("        ${1}(chn, null ${2});", mname, sb2);
			sb.pn("        if(chn == null) return;");
			sb.pn("        Map _params = new HashMap();");
			sb.pn("        _params.put(${1}, ${2}); // cmd:${3}", B3G.METHOD,
					hmname, mname);
			int i = 0;
			for (NewMap<String, String> m1 : params) {
				String key = (String) m1.getKey();
				String val = (String) m1.getValue();
				int hval = val.hashCode();
				if (B3G.getMapType(key).equals("getObject")) {
					sb.pn("        _params.put(${1}, ${2}.toMap());", hval, val);
				} else {
					if (B3G.getMapType(key).equals("getList")) {
						sb.pn("		{");
						sb.pn("			// Lsit对象(${1})", val);
						sb.pn("			List _list = new NewList();");
						String oType = B3G.getOType(m, val);
						String mType = B3G.getMapType(oType);
						sb.pn("			for (${1} object : ${2}) {", oType, val);
						if (mType.equals("getObject")) {
							sb.pn("            _list.add(object.toMap());");
						} else {
							sb.pn("            _list.add(object);");
						}
						sb.pn("			}");
						sb.pn("			_params.put(${1}, _list);", hval);
						sb.pn("		}");
					} else {
						sb.pn("        _params.put(${1}, ${2});", hval, val);
					}
				}
				i++;
			}
			sb.pn("        chn.send(_params);");
			sb.pn("    }");
		}

		StrBuilder sb2 = new StrBuilder();
		StrBuilder sb3 = new StrBuilder();
		StrBuilder sb4 = new StrBuilder();
		for (Method m : methods) {
			String rtype = B3G.getReturnType(m);
			if (B3G.isClient(m) && rtype.equals("void"))
				continue;
			String mname = B3G.getNethodName(m);
			int hmname = hashCode(cname, mname);
			sb2.ap("${1},", hmname);
			sb3.ap(".put2(${1}, $[2])", hmname, mname);
			if (B3G.isWriteOp(m))
				sb4.ap("${1},", hmname);
		}
		if (sb2.len() > 1)
			sb2.removeRight(1);
		if (sb4.len() > 1)
			sb4.removeRight(1);
		String s = sb2.toString();
		String sNames = sb3.toString();
		String sWrites = sb4.toString();

		sb.pn("");
		sb.pn("    public static final Set<Integer> CMD = NewSet.create(${1});",
				s);
		sb.pn("    public static final Map<Integer, String> NAMES = NewMap.create()${1};",
				sNames);
		sb.pn("    public static final Set<Integer> WRITES = NewSet.create(${1});",
				sWrites);
		sb.pn("");
		sb.pn("    public String getMethodName(int cmd) {");
		sb.pn("        return NAMES.get(cmd);");
		sb.pn("    }");
		sb.pn("");
		sb.pn("    public boolean isWriteMethod(int cmd) {");
		sb.pn("        return WRITES.contains(cmd);");
		sb.pn("    }");
		sb.pn("");
		sb.pn("    public boolean in(NewMap map) throws Exception {");
		sb.pn("        int cmd = map.getInt(${1});", B3G.METHOD);
		sb.pn("        return CMD.contains(cmd);");
		sb.pn("    }");
		sb.pn("");

		sb.pn("    public boolean in(int cmd) throws Exception {");
		sb.pn("        return CMD.contains(cmd);");
		sb.pn("    }");
		sb.pn("");
		// sb.pn("    public abstract java.io.ByteArrayOutputStream getOutStream();");
		// sb.pn("    public abstract void freeOutStream(java.io.ByteArrayOutputStream baos);");
		// sb.pn("");

		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("    // 逻辑分发");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("");
		sb.pn("    public int disp(TcpChannel chn, NewMap map) throws Exception {");
		sb.pn("        if(chn == null) return 0;");
		sb.pn("        int cmd = map.getInt(${1});", B3G.METHOD);
		sb.pn("        return disp(chn, cmd, map);");
		sb.pn("    }");
		sb.pn("    public int disp(TcpChannel chn, int cmd, NewMap map) throws Exception {");
		sb.pn("        if(chn == null) return 0;");
		sb.pn("        switch (cmd) {");
		for (Method m : methods) {
			String remark = B3G.getRemark(m);
			String srtype = B3G.getReturnType(m);
			String mname = B3G.getNethodName(m);
			int hmname = hashCode(cname, mname);
			if (B3G.isServer(m)) {
				sb.pn("            case ${1}: { //  ${2}", hmname, remark);
				sb.pn("                return __${1}(chn, map);", mname);
				sb.pn("                // return \"${1}\";", mname);
				sb.pn("            }");
			} else {
				if (!srtype.equals("void")) {
					sb.pn("            case ${1}: { //  ${2}", hmname, remark);
					sb.pn("                __onCallback_${1}(chn, map);", mname);
					sb.pn("                return 0;");
					sb.pn("                //return \"${1}\";", mname);
					sb.pn("            }");
				}
			}
		}
		sb.pn("        }");
		sb.pn("        throw new Exception(\" cmd: \" + cmd + \":\" + map + \" not found processor.\");");
		sb.pn("    }");
		sb.pn("");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("    // 解析参数");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("");
		for (Method m : methods) {
			String remark = B3G.getRemark(m);
			// String oType = B2G.getOType(m);
			String srtype = B3G.getReturnType(m);
			String mname = B3G.getNethodName(m);
			String hmname = hashCode(cname, mname) + "";
			NewList<NewMap<String, String>> params = B3G.getParameters(m);

			StrBuilder sb1 = new StrBuilder();

			// 解析参数函数
			sb.pn("    // ${1}", remark);
			if (B3G.isClient(m)) {
				if (!srtype.equals("void")) {
					String mx = B3G.getMapType(srtype);

					sb.pn("    private void __onCallback_${1}(TcpChannel chn, NewMap map2) throws Exception {",
							mname);
					sb.pn("        if(chn == null) return;");
					// sb.pn("        NewMap map2 = NewMap.create(map);");
					sb.pn("        NewMap retVal = map2.getNewMap(1);", srtype,
							mx);
					sb.pn("");
					sb.pn("        ${1} rst = ${1}.parse(retVal);", retname);
					sb.pn("");
					sb.pn("        on${1}(chn, rst);", upper1(mname));
					sb.pn("    }");
				}
			} else {
				sb.pn("    private int __${1}(TcpChannel chn, NewMap map2) throws Exception {",
						mname);
				sb.pn("        if(chn == null) return 0;");
				// if (!params.isEmpty()) {
				// sb.pn("        NewMap map2 = NewMap.create(map);");
				// sb.pn("");
				// }

				StringBuffer sbThrow = new StringBuffer("Object[] othrows = {");

				int nOutNum = 0;
				for (NewMap<String, String> m1 : params) {
					String key = (String) m1.getKey();
					String val = (String) m1.getValue();
					String hval = val.hashCode() + "";
					String p = B3G.getMapType(key);
					boolean isOut = B3G.isOut(m, val);
					if (isOut) {
						sb.pn("        ${1} ${2} = new ${1}();", key, val);
						nOutNum++;
					} else {
						if (p.equals("getObject")) {
							sb.pn("        ${1} ${2} = ${1}.parse(map2.getNewMap(${3}));",
									key, val, hval);
						} else {

							if (p.equals("getList")) {
								String oType = B3G.getOType(m, val);
								String mType = B3G.getMapType(oType);
								if (mType.equals("getObject")) {
									sb.pn("        ${1}<${2}> ${3} = new NewList<${2}>();",
											key, oType, val);
									sb.pn("        {");
									sb.pn("            List<NewMap> maps = map2.${1}(${2});",
											p, hval);
									sb.pn("            for(NewMap m1 : maps) {");
									sb.pn("                ${1}.add(${2}.parse(m1));",
											val, oType);
									sb.pn("            }");
									sb.pn("        }");
									key = PStr.str("${1}<${2}>", key, oType);
								} else {
									sb.pn("        ${1} ${2} = map2.${3}(${4});",
											key, val, p, hval);

								}
							} else {
								sb.pn("        ${1} ${2} = map2.${3}(${4});",
										key, val, p, hval);
							}
						}
					}
					sb1.ap(", ${1}", val);

					sbThrow.append("\"\\\"").append(val).append(":\\\"\", ")
							.append(val).append(", ");
				}

				sbThrow.append("};");

				sb.pn("");
				if (srtype.equals("void")) {
					sb.pn("        try {");
					sb.pn("            on${1}(chn${2});", upper1(mname), sb1);
					sb.pn("        } catch ( Exception e ) {");
					sb.pn("            ${1}", sbThrow);
					sb.pn("            onExcept(chn, $[1], Log.rethrow2(e, $[1], othrows), null);",
							mname);
					sb.pn("        }");
				} else {
					sb.pn("        ${1} rst = new ${1}();", srtype);
					// sb.pn("        rst = on${1}(chn${2}, rst);",
					// upper1(mname), sb1);
					sb.pn("        try {");
					sb.pn("            on${1}(chn${2}, rst);", upper1(mname),
							sb1);
					sb.pn("        } catch ( Exception e ) {");
					sb.pn("            ${1}", sbThrow);
					sb.pn("            onExcept(chn, $[1], Log.rethrow2(e, $[1], othrows), rst);",
							mname);
					sb.pn("        }");
					sb.pn("        try ( ByteOutStream result = getStream();) {");
					sb.pn("            writeMapTag(result, ${1});", nOutNum + 2);
					sb.pn("            writeMapEntry(result, ${1}, ${2});",
							B3G.METHOD, hmname);
					sb.pn("            writeMapEntry(result, ${1}, rst.toMap());",
							B3G.RETURN_STAT);
					for (NewMap<String, String> m1 : params) {
						String key = (String) m1.getKey();
						String val = (String) m1.getValue();
						String hval = val.hashCode() + "";
						String p = B3G.getMapType(key);
						boolean isOut = B3G.isOut(m, val);
						if (isOut) {
							sb.pn("            writeMapEntry(result, ${1}, ${2}.toMap());",
									hval, val);
						}
					}
					sb.pn("            return chn.send(result.toByteArray());");
					sb.pn("        } catch (Exception e) {");
					sb.pn("            throw e;");
					sb.pn("        }");
					// sb.pn("        Map result = new HashMap();");
					// sb.pn("        result.put(${1}, ${2});", B2G.METHOD,
					// hmname);
					// sb.pn("        result.put(${1}, rst.toMap());",
					// B2G.RETURN_STAT);
					// for (NewMap<String, String> m1 : params) {
					// String key = (String) m1.getKey();
					// String val = (String) m1.getValue();
					// String hval = val.hashCode() + "";
					// String p = B2G.getMapType(key);
					// boolean isOut = B2G.isOut(m, val);
					// if (isOut) {
					// sb.pn("        result.put(${1}, ${2}.toMap());",
					// hval, val);
					// }
					// }

				}
				sb.pn("    }");

				if (B3G.isServer(m)) {
					if (!srtype.equals("void")) {
						StrBuilder msb = new StrBuilder();
						for (NewMap<String, String> m1 : params) {
							String key = (String) m1.getKey();
							String val = (String) m1.getValue();
							String hval = val.hashCode() + "";
							String p = B3G.getMapType(key);
							boolean isOut = B3G.isOut(m, val);
							if (isOut) {
								if (p.equals("getObject")) {
									msb.ap(", ${1} ${2}", key, val);
								}
							}
						}

						// sb.pn("    public void on${1}(${2}${3} val) throws Exception {};",
						// upper1(mname), msb, srtype);
						// sb.pn("    public void snd${1}(TcpChannel chn${2}) {",
						// upper1(mname), msb);
						// if (srtype.equals("void")) {
						// sb.pn("        on${1}(chn${2});", upper1(mname),
						// sb1);
						// } else {
						// sb.pn("        ${1} rst = new ${1}();", srtype);
						// sb.pn("        rst = on${1}(chn${2}, rst);",
						// upper1(mname),
						// sb1);
						// sb.pn("        Map result = new NewMap();");
						// sb.pn("        result.put(${1}, ${2});", B2G.METHOD,
						// hmname);
						// sb.pn("        result.put(${1}, rst.toMap());",
						// B2G.RETURN_STAT);
						// for (NewMap<String, String> m1 : params) {
						// String key = (String) m1.getKey();
						// String val = (String) m1.getValue();
						// String hval = val.hashCode() + "";
						// String p = B2G.getMapType(key);
						// boolean isOut = B2G.isOut(m, val);
						// if (isOut) {
						// sb.pn("        result.put(${1}, ${2}.toMap());",
						// hval, val);
						// }
						// }
						//
						// sb.pn("        chn.send(result);");
						//
						// sb.pn("    }");
					}
					sb.pn("");
				}
			}
		}

		// A////////////////////////////////////////////////
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("    // 逻辑分发");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("");
		sb.pn("    public String _params(NewMap map) throws Exception {");
		sb.pn("        int cmd = map.getInt(${1});", B3G.METHOD);
		sb.pn("        return _params(cmd, map);");
		sb.pn("    }");
		sb.pn("    public String _params(int cmd, NewMap map) throws Exception {");
		sb.pn("        switch (cmd) {");
		for (Method m : methods) {
			String remark = B3G.getRemark(m);
			String srtype = B3G.getReturnType(m);
			String mname = B3G.getNethodName(m);
			int hmname = hashCode(cname, mname);
			if (B3G.isServer(m)) {
				sb.pn("            case ${1}: { //  ${2}", hmname, remark);
				sb.pn("                return __${1}_params(map);", mname);
				sb.pn("            }");
			}
		}
		sb.pn("        }");
		sb.pn("        throw new Exception(\" cmd: \" + cmd + \":\" + map + \" not found processor.\");");
		sb.pn("    }");
		sb.pn("");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("    // 解析参数 X");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("");
		for (Method m : methods) {
			String remark = B3G.getRemark(m);
			// String oType = B2G.getOType(m);
			String srtype = B3G.getReturnType(m);
			String mname = B3G.getNethodName(m);
			int hmname = hashCode(cname, mname);
			NewList<NewMap<String, String>> params = B3G.getParameters(m);

			StrBuilder sb1 = new StrBuilder();

			// 解析参数函数
			sb.pn("    // ${1}", remark);
			sb.pn("    private static String __${1}_params(NewMap map2) throws Exception {",
					mname);
			StrBuilder sbT = new StrBuilder();
			sbT.an("        StringBuffer sb = com.bowlong.objpool.StringBufPool.borrowObject();");
			sbT.an("        try {");
			sbT.pn("            sb.append(\"${1}(\");", mname);
			int nOutNum = 0;
			for (NewMap<String, String> m1 : params) {
				String key = (String) m1.getKey();
				String val = (String) m1.getValue();
				String hval = val.hashCode() + "";
				String p = B3G.getMapType(key);
				boolean isOut = B3G.isOut(m, val);
				if (isOut) {
					// sb.pn("        ${1} ${2} = new ${1}();", key, val);
					nOutNum++;
				} else {
					if (p.equals("getObject")) {
						sb.pn("        ${1} ${2} = ${1}.parse(map2.getNewMap(${3}));",
								key, val, hval);
					} else {

						if (p.equals("getList")) {
							String oType = B3G.getOType(m, val);
							String mType = B3G.getMapType(oType);
							if (mType.equals("getObject")) {
								sb.pn("        ${1}<${2}> ${3} = new NewList<${2}>();",
										key, oType, val);
								sb.pn("        {");
								sb.pn("            List<NewMap> maps = map2.${1}(${2});",
										p, hval);
								sb.pn("            for(NewMap m1 : maps) {");
								sb.pn("                ${1}.add(${2}.parse(m1));",
										val, oType);
								sb.pn("            }");
								sb.pn("        }");
								key = PStr.str("${1}<${2}>", key, oType);
							} else {
								sb.pn("        ${1} ${2} = map2.${3}(${4});",
										key, val, p, hval);

							}
						} else {
							sb.pn("        ${1} ${2} = map2.${3}(${4});", key,
									val, p, hval);
						}
					}
					sb1.ap(", ${1}", val);
					sbT.pn("            sb.append(\"\\\"${1}\\\":\").append(${1}).append(\",\");",
							val);
				}
			}
			sbT.pn("            sb.append(\")\");");
			sbT.pn("            return sb.toString();");
			sbT.an("        } finally {");
			sbT.an("            com.bowlong.objpool.StringBufPool.returnObject(sb);");
			sbT.an("        }");

			sb.pn(sbT.str());
			sb.pn("    }");
		}
		// A////////////////////////////////////////////////

		sb.pn("");
		sb.pn("    public static Exception rethrow(Exception cause, String method, Object... params) {");
		sb.pn("        String causeMessage = cause.getMessage();");
		sb.pn("        if (causeMessage == null) {");
		sb.pn("            causeMessage = \"\";");
		sb.pn("        }");
		sb.pn("        StringBuffer msg = new StringBuffer(causeMessage);");
		sb.pn("        msg.append(\"\\r\\n\");");
		sb.pn("        msg.append(method);");
		sb.pn("        msg.append(\" Parameters: \");");
		sb.pn("        msg.append(\"\\r\\n\");");
		sb.pn("        if (params == null) {");
		sb.pn("            msg.append(\"[]\");");
		sb.pn("        } else {");
		sb.pn("            msg.append(Arrays.deepToString(params));");
		sb.pn("        }");
		sb.pn("        msg.append(\"\\r\\n\");");
		sb.pn("        Exception e = new Exception(msg.toString(), cause);");
		sb.pn("        return e;");
		sb.pn("    }");
		sb.pn("");
		sb.pn("");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("    // 需要实现的接口");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("");
		sb.pn("    public abstract void onExcept(TcpChannel chn, String method, String except, ${1} ret) throws Exception;",
				retname);
		for (Method m : methods) {
			String remark = B3G.getRemark(m);
			// String oType = B2G.getOType(m);
			String srtype = B3G.getReturnType(m);
			String mname = B3G.getNethodName(m);
			NewList<NewMap<String, String>> params = B3G.getParameters(m);

			StrBuilder sb1 = new StrBuilder();
			for (NewMap<String, String> m1 : params) {
				String key = (String) m1.getKey();
				String val = (String) m1.getValue();
				String p = B3G.getMapType(key);
				if (p.equals("getList") && !"".equals(B3G.getOType(m, val))) {
					key = PStr.str("${1}<${2}>", key, B3G.getOType(m, val));
				}
				sb1.ap(", ${1} ${2}", key, val);
			}

			// 需要实现的逻辑函数
			if (B3G.isServer(m)) {
				sb.pn("    // ${1}", remark);
				if (!srtype.equals("void")) {
					sb.pn("    public abstract void on${2}(TcpChannel chn ${3}, ${1} ret) throws Exception;",
							srtype, upper1(mname), sb1);
				} else {
					sb.pn("    public abstract void on${2}(TcpChannel chn ${3}) throws Exception;",
							srtype, upper1(mname), sb1);
				}
			} else {
				if (!srtype.equals("void")) {
					sb.pn("    // ${1}", remark);
					sb.pn("    public void on${1}(TcpChannel chn, ${2} val) throws Exception { };",
							upper1(mname), srtype);
				}
			}
		}
		sb.pn("}");
	}

	// 生成客户端接口
	public static void g2s_call(Class<?> c, String namespace, String retname,
			StrBuilder sb) {
		String sname = c.getSimpleName();
		Method[] methods = c.getMethods();
		String cname = c.getSimpleName();
		sb.pn("package gen_b2g${1};", StrEx.isEmpty(namespace) ? "" : "."
				+ namespace);
		// sb.pn("package gen_b2g;");
		sb.pn("");
		// sb.pn("import java.io.*;");
		sb.pn("import java.util.*;");
		sb.pn("");
		// sb.pn("import com.bowlong.io.*;");
		sb.pn("import com.bowlong.util.*;");
		sb.pn("import com.bowlong.net.*;");
		sb.pn("");
		sb.pn("import gen_b2g${1}.bean.*;", StrEx.isEmpty(namespace) ? "" : "."
				+ namespace);
		sb.pn("");
		sb.pn("@SuppressWarnings({ \"rawtypes\", \"unchecked\" })");
		sb.pn("public abstract class Call${1} {", cname);

		sb.pn("");
		sb.pn("    public static int __pid;");
		sb.pn("    public TcpChannel chn;");
		sb.pn("    public Call${1}(TcpChannel chn) {", sname);
		sb.pn("        this.chn = chn;");
		sb.pn("    }");
		sb.pn("");
		for (Method m : methods) {
			if (!B3G.isServer(m))
				continue;
			if (B3G.isAsync(m)) {
				String remark = B3G.getRemark(m);
				// String oType = B2G.getOType(m);
				String srtype = B3G.getReturnType(m);
				String mname = B3G.getNethodName(m);
				String hhmname = hashCode(cname, mname) + "";
				NewList<NewMap<String, String>> params = B3G.getParameters(m);

				StrBuilder sb1 = new StrBuilder();
				for (NewMap<String, String> m1 : params) {
					String mykey = (String) m1.getKey();
					String myvar = (String) m1.getValue();
					String hval = myvar.hashCode() + "";
					boolean isOut = B3G.isOut(m, myvar);
					if (isOut) {

					} else {
						if (mykey.equals("List")
								&& !"".equals(B3G.getOType(m, myvar))) {
							mykey = PStr.str("${1}<${2}>", mykey,
									B3G.getOType(m, myvar));
						}
						sb1.ap("${1} ${2}, ", mykey, myvar);
					}
				}
				if (sb1.length() > 2) {
					sb1.removeRight(2);
				}

				// 需要实现的逻辑函数
				sb.pn("    // ${1}", remark);
				sb.pn("    public void ${1}(${2}) throws Exception {", mname,
						sb1);
				sb.pn("        Map _map = new HashMap();");
				sb.pn("        _map.put(-100, __pid);  // _pid");
				sb.pn("        _map.put(${1}, ${2});  // cmd:${3}", B3G.METHOD,
						hhmname, mname);
				for (NewMap<String, String> m1 : params) {
					String key = (String) m1.getKey();
					String val = (String) m1.getValue();
					String p = B3G.getMapType(key);
					String hval = val.hashCode() + "";
					boolean isOut = B3G.isOut(m, val);
					if (isOut) {

					} else {
						if (p.equals("getList")) {
							String oType = B3G.getOType(m, val);
							String mType = B3G.getMapType(oType);
							if (mType.equals("getObject")) {
								sb.pn("		{");
								sb.pn("			// Lsit对象(${1})", val);
								sb.pn("		    List<Map> ${1}_list = new NewList<Map>();",
										val);
								sb.pn("        _map.put(${1}, ${2});", hval,
										val);
								sb.pn("        _map.put(${1}, ${2}_list);",
										hval, val);
								sb.pn("			for(${1} obj : ${2}) {", oType, val);
								sb.pn("				${1}_list.add(obj.toMap());", val,
										oType);
								sb.pn("			}");
								sb.pn("		}");
								val += "_list";
							} else {
							}
						} else if (B3G.getMapType(key).equals("getObject")) {
							sb.pn("        _map.put(${1}, ${2}.toMap());",
									hval, val);
						} else {
							sb.pn("        _map.put(${1}, ${2});", hval, val);
						}
					}
				}
				sb.pn("        chn.send(_map);");
				sb.pn("    }");
				sb.pn("");
				// end async
			} else { // sync

				if (!B3G.isServer(m))
					continue;

				String remark = B3G.getRemark(m);
				// String oType = B2G.getOType(m);
				String srtype = B3G.getReturnType(m);
				String mname = B3G.getNethodName(m);
				String hhmname = hashCode(cname, mname) + "";
				NewList<NewMap<String, String>> params = B3G.getParameters(m);

				StrBuilder sb1 = new StrBuilder();
				StrBuilder sb2 = new StrBuilder();
				for (NewMap<String, String> m1 : params) {
					String mykey = (String) m1.getKey();
					String myvar = (String) m1.getValue();
					String hval = myvar.hashCode() + "";
					boolean isOut = B3G.isOut(m, myvar);
					if (mykey.equals("List")
							&& !"".equals(B3G.getOType(m, myvar))) {
						mykey = PStr.str("${1}<${2}>", mykey,
								B3G.getOType(m, myvar));
					}
					sb1.ap("${1} ${2}, ", mykey, myvar);
					sb2.ap("${2}, ", mykey, myvar);
				}
				if (sb1.length() > 2)
					sb1.removeRight(2);
				if (sb2.length() > 2)
					sb2.removeRight(2);

				// 需要实现的逻辑函数
				sb.pn("    // ${1}", remark);
				if (B3G.isRetry(m)) {
					sb.pn("    public synchronized ${3} ${1}(${2}) throws Exception {",
							mname, sb1, retname);
					sb.pn("        try {");
					sb.pn("            return __${1}(${2});", mname, sb2);
					sb.pn("        } catch (Exception e) {");
					sb.pn("            try {");
					sb.pn("                return __${1}(${2});", mname, sb2);
					sb.pn("            } catch (Exception e2) {");
					sb.pn("               throw e2;");
					sb.pn("            }");
					sb.pn("        }");
					sb.pn("    }");
					sb.pn("    // ${1}", remark);
					sb.pn("    ${3} __${1}(${2}) throws Exception {", mname,
							sb1, retname);
				} else {
					sb.pn("    public synchronized ${3} ${1}(${2}) throws Exception {",
							mname, sb1, retname);
				}
				sb.pn("        { // send");
				sb.pn("          Map _map = new HashMap();");
				sb.pn("          _map.put(-100, __pid);  // _pid");
				sb.pn("          _map.put(${1}, ${2});  // cmd:${3}",
						B3G.METHOD, hhmname, mname);
				for (NewMap<String, String> m1 : params) {
					String key = (String) m1.getKey();
					String val = (String) m1.getValue();
					String p = B3G.getMapType(key);
					String hval = val.hashCode() + "";
					boolean isOut = B3G.isOut(m, val);
					if (isOut) {

					} else {
						if (p.equals("getList")) {
							String oType = B3G.getOType(m, val);
							String mType = B3G.getMapType(oType);
							if (mType.equals("getObject")) {
								sb.pn("		{");
								sb.pn("		    // Lsit对象(${1})", val);
								sb.pn("		    List<Map> ${1}_list = new NewList<Map>();",
										val);
								sb.pn("        _map.put(${1}, ${2});", hval,
										val);
								sb.pn("        _map.put(${1}, ${2}_list);",
										hval, val);
								sb.pn("			for(${1} obj : ${2}) {", oType, val);
								sb.pn("				${1}_list.add(obj.toMap());", val,
										oType);
								sb.pn("			}");
								sb.pn("		}");
								val += "_list";
							} else {
							}
						} else if (B3G.getMapType(key).equals("getObject")) {
							sb.pn("          _map.put(${1}, ${2}.toMap());",
									hval, val);
						} else {
							sb.pn("          _map.put(${1}, ${2});", hval, val);
						}
					}
				}
				sb.pn("          chn.send(_map);");
				sb.pn("        }");
				sb.pn("        { // recv");
				sb.pn("          NewMap map2 = chn.readMap();");
				sb.pn("          NewMap retVal = map2.getNewMap(${1});",
						B3G.RETURN_STAT);
				sb.pn("          ${1} rst = ${1}.parse(retVal);", retname);
				sb.pn("          if(rst.succ >= 0) {");
				StrBuilder msb = new StrBuilder();
				for (NewMap<String, String> m1 : params) {
					String key = (String) m1.getKey();
					String val = (String) m1.getValue();
					String hval = val.hashCode() + "";
					String p = B3G.getMapType(key);
					boolean isOut = B3G.isOut(m, val);
					if (isOut) {
						if (p.equals("getObject")) {
							sb.pn("            ${1}.parse(map2.getNewMap(${3}), ${2});",
									key, val, hval);
							msb.ap("${1}, ", val);
						}
					}
				}
				sb.pn("          }");
				sb.pn("");
				sb.pn("          return rst;");
				sb.pn("        }");
				sb.pn("    }");
				sb.pn("");

				// end sync
			}
		}

		StrBuilder sb2 = new StrBuilder();
		for (Method m : methods) {
			if (B3G.isSync(m))
				continue;
			String rtype = B3G.getReturnType(m);
			if (B3G.isServer(m) && rtype.equals("void"))
				continue;
			String mname = B3G.getNethodName(m);
			String hmane = hashCode(cname, mname) + "";
			sb2.ap("${1},", hmane);
		}
		if (sb2.len() > 2)
			sb2.removeRight(1);
		String s = sb2.toString();

		sb.pn("");
		sb.pn("    public static final Set<Integer> CMD = NewSet.create(${1});",
				s);
		sb.pn("");
		sb.pn("    public static boolean in(NewMap map) throws Exception {");
		sb.pn("        int cmd = map.getInt(${1});", B3G.METHOD);
		sb.pn("        return CMD.contains(cmd);");
		sb.pn("    }");
		sb.pn("");

		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("    // 逻辑分发");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("");
		sb.pn("    public void disp(NewMap map) throws Exception {");
		sb.pn("        int cmd = map.getInt(${1});", B3G.METHOD);
		sb.pn("        disp(cmd, map);");
		sb.pn("    }");
		sb.pn("    public void disp(int cmd, NewMap map) throws Exception {");
		sb.pn("        switch (cmd) {");
		for (Method m : methods) {
			if (B3G.isSync(m))
				continue;

			String remark = B3G.getRemark(m);
			String srtype = B3G.getReturnType(m);
			String mname = B3G.getNethodName(m);
			int hmname = hashCode(cname, mname);
			if (B3G.isServer(m)) {
				if (!srtype.equals("void")) {
					sb.pn("            case ${1}: { //  ${2}", hmname, remark);
					sb.pn("                __onCallback_${1}(map);", mname);
					sb.pn("                return;");
					sb.pn("            }");
				}
			} else {
				sb.pn("            case ${1}: { //  ${2}", hmname, remark);
				sb.pn("                __onCall_${1}(map);", mname);
				sb.pn("                return;");
				sb.pn("            }");
			}
		}
		sb.pn("        }");
		sb.pn("        throw new Exception(\" cmd: \" + cmd + \":\" + map + \" not found processor.\");");
		sb.pn("    }");
		sb.pn("");
		sb.pn("");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("    // 参数解析");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("");
		for (Method m : methods) {
			if (B3G.isSync(m))
				continue;

			String remark = B3G.getRemark(m);
			// String oType = B2G.getOType(m);
			String srtype = B3G.getReturnType(m);
			String mname = B3G.getNethodName(m);
			String hmname = hashCode(cname, mname) + "";
			NewList<NewMap<String, String>> params = B3G.getParameters(m);

			// 解析参数函数
			if (B3G.isServer(m)) {
				if (!srtype.equals("void")) {
					sb.pn("    // ${1}", remark);
					sb.pn("    private void __onCallback_${1}(NewMap map2) throws Exception {",
							mname);
					String mx = B3G.getMapType(srtype);
					// sb.pn("        NewMap map2 = NewMap.create(map);");
					sb.pn("        NewMap retVal = map2.getNewMap(${1});",
							B3G.RETURN_STAT);
					sb.pn("        ${1} rst = ${1}.parse(retVal);", retname);

					boolean haveIsOut = false;
					StrBuilder msb = new StrBuilder();
					for (NewMap<String, String> m1 : params) {
						String key = (String) m1.getKey();
						String val = (String) m1.getValue();
						String hval = val.hashCode() + "";
						String p = B3G.getMapType(key);
						boolean isOut = B3G.isOut(m, val);
						if (isOut) {
							if (p.equals("getObject")) {
								haveIsOut = true;
								sb.pn("        ${1} ${2} = null; // def var",
										key, val);
								msb.ap("${1}, ", val);
							}
						}
					}
					if (haveIsOut) {
						sb.pn("        if(rst.succ >= 0) {");

						for (NewMap<String, String> m1 : params) {
							String key = (String) m1.getKey();
							String val = (String) m1.getValue();
							String hval = val.hashCode() + "";
							String p = B3G.getMapType(key);
							boolean isOut = B3G.isOut(m, val);
							if (isOut) {
								if (p.equals("getObject")) {
									sb.pn("          ${2} = ${1}.parse(map2.getNewMap(${3}));",
											key, val, hval);
								}
							}
						}
						sb.pn("        }");
					}
					sb.pn("");
					sb.pn("        on${1}(${2}rst);", upper1(mname), msb);
					sb.pn("    }");
				}
			} else {
				sb.pn("    // ${1}", remark);
				sb.pn("    private void __onCall_${1}(NewMap map2) throws Exception {",
						mname);
				// sb.pn("        NewMap map2 = NewMap.create(map);");
				sb.pn("");
				StrBuilder sb1 = new StrBuilder();
				for (NewMap<String, String> m1 : params) {
					String key = (String) m1.getKey();
					String val = (String) m1.getValue();
					String hval = val.hashCode() + "";
					String p = B3G.getMapType(key);
					boolean isOut = B3G.isOut(m, val);

					if (p.equals("getObject")) {
						sb.pn("        ${1} ${2} = ${1}.parse(map2.getNewMap(${3}));",
								key, val, hval);
					} else {
						sb.pn("        ${1} ${2} = map2.${3}(${4});", key, val,
								p, hval);
						if (p.equals("getList")) {
							String oType = B3G.getOType(m, val);
							String mType = B3G.getMapType(oType);
							sb.pn("		List<${1}> ${2}_list = new NewList<${3}>();",
									oType, val, oType);
							sb.pn("		{");
							sb.pn("			// Lsit对象(${1})", val);
							sb.pn("			for(Object obj : ${1}) {", val);
							if (mType.equals("getObject"))
								sb.pn("				${1}_list.add(${2}.parse((NewMap)obj));",
										val, oType);
							else
								sb.pn("				${1}_list.add((${2})obj);", val,
										oType);

							sb.pn("			}");
							sb.pn("		}");
							val += "_list";
						}
					}
					sb1.ap("${1}, ", val);
				}
				if (sb1.length() > 2)
					sb1.removeRight(2);

				sb.pn("");
				if (srtype.equals("void")) {
					sb.pn("        on${1}(${2});", upper1(mname), sb1);
				} else {

					sb.pn("        ${3} rst = on${1}(${2});", upper1(mname),
							sb1, retname);

					sb.pn("        Map result = new HashMap();");
					sb.pn("        result.put(${1}, ${2});", B3G.METHOD, hmname);
					sb.pn("        result.put(${1}, rst.toMap());",
							B3G.RETURN_STAT);
					sb.pn("        chn.send(result);");
				}
				sb.pn("    }");
			}
			sb.pn("");
		}

		sb.pn("");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("    // 需要实现的接口");
		sb.pn("    // //////////////////////////////////////////////");
		sb.pn("");
		for (Method m : methods) {
			if (B3G.isSync(m))
				continue;

			String remark = B3G.getRemark(m);
			// String oType = B2G.getOType(m);
			String srtype = B3G.getReturnType(m);
			String mname = B3G.getNethodName(m);
			NewList<NewMap<String, String>> params = B3G.getParameters(m);
			// 解析参数函数
			sb.pn("    // ${1}", remark);
			if (B3G.isServer(m)) {
				if (!srtype.equals("void")) {
					StrBuilder msb = new StrBuilder();
					for (NewMap<String, String> m1 : params) {
						String key = (String) m1.getKey();
						String val = (String) m1.getValue();
						String hval = val.hashCode() + "";
						String p = B3G.getMapType(key);
						boolean isOut = B3G.isOut(m, val);
						if (isOut) {
							if (p.equals("getObject")) {
								msb.ap("${1} ${2}, ", key, val);
							}
						}
					}

					sb.pn("    public void on${1}(${2}${3} val) throws Exception {};",
							upper1(mname), msb, srtype);
				}
			} else {

				StrBuilder sb1 = new StrBuilder();
				for (NewMap<String, String> m1 : params) {
					String key = (String) m1.getKey();
					String val = (String) m1.getValue();
					if (B3G.getMapType(key).equals("getList")) {
						key = PStr.str("${1}<${2}>", key, B3G.getOType(m, val));
					}
					sb1.ap("${1} ${2}, ", key, val);
				}
				if (sb1.length() > 2) {
					sb1.removeRight(2);
				}

				// 需要实现的逻辑函数
				sb.pn("    public abstract ${1} on${2}(${3}) throws Exception;",
						srtype, upper1(mname), sb1);

			}
			sb.pn("");
		}
		sb.pn("}");
	}

	public static void writeFile(String f, String str) {
		try (FileOutputStream out = new FileOutputStream(new File(f));
				OutputStreamWriter osw = new OutputStreamWriter(out,
						Charset.forName("UTF8"));) {
			osw.write(str, 0, str.length());
			osw.close();
			out.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public static String upper1(String s) {
		if (s == null || s.isEmpty())
			return s;
		int len = s.length();
		return s.substring(0, 1).toUpperCase() + s.substring(1, len);
	}

	static String getSheetIndexMethod(String cname, Map map) {
		String type = MapEx.getString(map, "type"); // ix , ux
		List<Map> fields = MapEx.getList(map, "fields");

		String ret = getSheetIndexReturn(cname, type);
		String method = getSheetIndexMethodName(fields);
		String params = getSheetIndeParams(fields);
		StrBuilder sb = new StrBuilder();
		sb.a(ret).a(" ").a(method).a("(").a(params).a(")");
		return sb.str();
	}

	static String getSheetIndexReturn(String cname, String type) {
		if (type.equals("ix")) {
			return "List<" + cname + ">";
		} else if (type.equals("ux")) {
			return cname;
		}

		return "";
	}

	static String getSheetIndexReturnInit(String cname, String type) {
		if (type.equals("ix")) {
			return "new ArrayList<" + cname + ">()";
		} else if (type.equals("ux")) {
			return "null";
		}

		return "";
	}

	static String getSheetIndexMethodName(List<Map> list) {
		if (isEmpty(list))
			return "";
		StrBuilder sb = new StrBuilder();
		sb.a("getBy");
		for (Map map : list) {
			String field = MapEx.getString(map, "field");
			String type = MapEx.getString(map, "type");
			String f = upperN1(lower(field));
			sb.a(f);
		}

		return sb.str();
		// [{"field":"GID","type":"int"},{"field":"Lvl","type":"int"}]
		// [{"field":"GID","type":"int"}]
	}

	static String getSheetIndexMethodEq(List<Map> list) {
		if (isEmpty(list))
			return "";
		StrBuilder sb = new StrBuilder();
		for (Map map : list) {
			String field = MapEx.getString(map, "field");
			String type = MapEx.getString(map, "type");
			String flow = lower(field);
			if (type.equals("int")) {
				sb.a("e.").a(field).a(" == ").a(flow).a(" && ");
			} else if (type.equals("boolean")) {
				sb.a("e.").a(field).a(" == ").a(flow).a(" && ");
			} else if (type.equals("String")) {
				sb.a("e.").a(field).a(".equals(").a(flow).a(") && ");
			}
		}
		if (sb.len() > 4)
			sb.removeRight(4);
		return sb.str();
		// [{"field":"GID","type":"int"},{"field":"Lvl","type":"int"}]
		// [{"field":"GID","type":"int"}]
	}

	static String getSheetIndeParams(List<Map> list) {
		if (isEmpty(list))
			return "";
		StrBuilder sb = new StrBuilder();
		sb.a("");
		for (Map map : list) {
			String field = MapEx.getString(map, "field");
			String type = MapEx.getString(map, "type");
			String f = lower(field);
			sb.a(type).a(" ").a(f).a(", ");
		}
		if (sb.len() > 2)
			sb.removeRight(2);
		return sb.str();
		// [{"field":"GID","type":"int"},{"field":"Lvl","type":"int"}]
		// [{"field":"GID","type":"int"}]
	}

	static String getSheetCallParams(List<Map> list) {
		if (isEmpty(list))
			return "";
		StrBuilder sb = new StrBuilder();
		sb.a("");
		for (Map map : list) {
			String field = MapEx.getString(map, "field");
			String f = lower(field);
			sb.a("\"").a(f).a(":\"").a(", ").a(f).a(", ");
		}
		if (sb.len() > 2)
			sb.removeRight(2);
		return sb.str();
		// [{"field":"GID","type":"int"},{"field":"Lvl","type":"int"}]
		// [{"field":"GID","type":"int"}]
	}

	static String getSheetIndexParams(List<Map> list) {
		if (isEmpty(list))
			return "";
		StrBuilder sb = new StrBuilder();
		sb.a("");
		for (Map map : list) {
			String field = MapEx.getString(map, "field");
			String f1 = lower(field);
			sb.a("\"").a(f1).a(":\"").a(", e.").a(field).a(", ");
		}
		if (sb.len() > 2)
			sb.removeRight(2);
		return sb.str();
		// [{"field":"GID","type":"int"},{"field":"Lvl","type":"int"}]
		// [{"field":"GID","type":"int"}]
	}

	static final int hashCode(String clazz) {
		return clazz.hashCode();
	}

	static final int hashCode(String clazz, String method) {
		String str = clazz + "." + method;
		return str.hashCode();
	}
}
